package com.ice.client.proto;

import com.ice.remoting.data.RemotingCommand;
import com.ice.remoting.utils.ModbusCrc16Utils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;

import java.nio.ByteOrder;

@Slf4j
public class ProtobufMsgDecode extends LengthFieldBasedFrameDecoder {

    /**
     * 起始符
     */
    final byte BEGIN_BYTE = 0x7E;
    // 最小长度
    final int MIN_LENGTH = 12;

    final byte UNIT_INDENTITY = 0x00;

    public ProtobufMsgDecode() {
        this(ByteOrder.BIG_ENDIAN, // byteOrder
                64 * 1024, // maxFrameLength
                5, // lengthFieldOffset
                2, // lengthFiledLength
                3, // lengthAdjustment 读取完长度域后剩下的所有的报文为后续报文
                0, // initialBytesToStrip
                false // failFast
        );
    }

    public ProtobufMsgDecode(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
        super(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf frame) throws Exception {
        frame = (ByteBuf) super.decode(ctx, frame);

        byte[] array = new byte[frame.readableBytes()];
        frame.readBytes(array);
        log.info("接收到待处理指令：" + Hex.toHexString(array));
        frame.resetReaderIndex();
        byte beginIndex = frame.readByte();
        if (array.length < MIN_LENGTH) {
            throw new DecoderException(String.format("报文异常：%s", Hex.toHexString(array)));
        }
        if (BEGIN_BYTE != beginIndex) {
            throw new DecoderException(String.format("报文异常：%s", Hex.toHexString(array)));
        }
        short tranId = frame.readShort(); // 事物ID
        short tcpIp = frame.readShort(); // tcp ip 协议
        short length = frame.readShort(); // 长度
        int readerIndex = frame.readerIndex();
        frame.skipBytes(length);
        byte[] crcArray = new byte[2];
        frame.readBytes(crcArray);
        String checkCrc = calcCrc16(frame, 7, length);
        if (!checkCrc.equals(Hex.toHexString(crcArray))) {
            throw new DecoderException("报文校验码校验错误");
        }
        frame.readerIndex(readerIndex);
        byte unitCent = frame.readByte(); // 单位标识符
        byte command = frame.readByte(); // 命令
        byte[] datas = null;
        if (length - 2 != 0) {
            datas = new byte[length - 2];
            frame.readBytes(datas);
        }
        readerIndex = frame.readerIndex();
        // 跳过
        frame.readerIndex(readerIndex + 3);
        RemotingCommand remotingCommand = new RemotingCommand();
        ProtobufHeader modbusHeader = new ProtobufHeader();
        modbusHeader.setLength(length);
        modbusHeader.setTid(tranId);
        modbusHeader.setVersion(tcpIp);
        modbusHeader.setUnitCert(unitCent);
        remotingCommand.setCommandCustomHeader(modbusHeader);
        remotingCommand.setCommand(command);
        remotingCommand.setOpaque(tranId);
        if (unitCent == UNIT_INDENTITY) {
            remotingCommand.getCommandCustomHeader().markResponseType();
        }
        remotingCommand.setBody(datas);
        return remotingCommand;
    }

    /**
     * 校验CRC
     *
     * @Author wangwei
     * @Date 2024/1/30
     */
    public static String calcCrc16(ByteBuf byteBuf, int offset, int byteLen) {
        int readIndex = byteBuf.readerIndex();
        byteBuf.resetReaderIndex();
        byteBuf.skipBytes(offset);
        byte[] bytes = new byte[byteLen];
        byteBuf.readBytes(bytes);
        byteBuf.readerIndex(readIndex);
        return ModbusCrc16Utils.getCrcString(bytes);
    }
}
